package cn.com.citydo.base.service.impl;

import cn.com.citydo.base.entity.BaseEntity;
import cn.com.citydo.base.query.QueryPage;
import cn.com.citydo.base.service.BaseCRUDService;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author XuJing
 * @since 2018-05-10 10:05
 */
public class BaseCRUDServiceImpl<M extends BaseMapper<T>, T extends BaseEntity> extends ServiceImpl<M, T> implements BaseCRUDService<T> {

    @Override
    public boolean save(T entity) {
        if (entity.getCreateTime() == null) {
            entity.setCreateTime(new Date());
        }
        if (entity.getModifyTime() == null) {
            entity.setModifyTime(new Date());
        }
        if (entity.getIsDel() == null) {
            entity.setIsDel(0);
        }
        Field[] fields = entity.getClass().getDeclaredFields();
        for (Field field : fields) {
            try {

                if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
                    //static 或 final 类型
                    continue;
                }
                ;

                if (!field.getGenericType().equals(String.class)) {
                    //非String类型
                    continue;
                }
                String methodName = field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                Method getMethod = entity.getClass().getMethod("get" + methodName);
                if (getMethod.invoke(entity) != null) {
                    //字段非空
                    continue;
                }
                Method method = entity.getClass().getMethod("set" + methodName, String.class);
                //非主键填充空字符串
                method.invoke(entity, "");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return retBool(baseMapper.insert(entity));
    }

    @Override
    public boolean updateById(T entity) {
        entity.setModifyTime(new Date());
        return retBool(baseMapper.updateById(entity));
    }

    @Override
    public IPage<T> listByPage(QueryPage queryPage) {
        QueryWrapper<T> wrapper = createPageWrapper(queryPage);
        wrapper = this.orderBy(queryPage, wrapper);
        if (queryPage.getOrderByCondition() == null || queryPage.getOrderByCondition().size() == 0) {
            wrapper.orderByDesc("create_time");
        }
        return selectByPage(queryPage, wrapper);
    }

    protected IPage<T> selectByPage(QueryPage queryPage, QueryWrapper<T> wrapper) {
        IPage<T> page = new Page<>(queryPage.getPage(), queryPage.getPageSize());
        page = baseMapper.selectPage(page, wrapper);
        return page;
    }

    protected QueryWrapper<T> orderBy(QueryPage queryPage, QueryWrapper<T> wrapper) {
        Map<String, Object> orderByMap = toUnderlineCase(queryPage.getOrderByCondition());
        for (String key : orderByMap.keySet()) {
            Boolean value = (Boolean) orderByMap.get(key);
            wrapper.orderBy(true, value, key);
        }
        return wrapper;
    }

    protected QueryWrapper<T> createPageWrapper(QueryPage queryPage) {
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        if (queryPage.getCondition() != null && queryPage.getCondition().size() > 0) {
            Map<String, Object> map = toUnderlineCase(queryPage.getCondition());
            wrapper.allEq(map);
        }

        if (queryPage.getRangeCondition() != null && queryPage.getRangeCondition().size() > 0) {
            Map<String, Object> rangeCondition = queryPage.getRangeCondition();
            for (String key : rangeCondition.keySet()) {
                String field = key.substring(3);
                String underline = StrUtil.toUnderlineCase(field);
                Object value = rangeCondition.get(key);
                if (key.startsWith("gt_")) {
                    wrapper.gt(underline, value);
                } else if (key.startsWith("ge_")) {
                    wrapper.ge(underline, value);
                } else if (key.startsWith("lt_")) {
                    wrapper.lt(underline, value);
                } else if (key.startsWith("le_")) {
                    wrapper.le(underline, value);
                }
            }
        }
        if (queryPage.getSearchCondition() != null && queryPage.getSearchCondition().size() > 0) {
            wrapper.and(w -> {
                Map<String, String> searchCondition = toUnderlineCase(queryPage.getSearchCondition());
                int index = 0;
                for (String key : searchCondition.keySet()) {
                    String value = searchCondition.get(key);
                    if (StringUtils.isBlank(value)) {
                        continue;
                    }
                    if (index > 0) {
                        w.or();
                    }
                    w.like(key, value);
                    index++;
                }
                return w;
            });
            //wrapper.andNew();
        }
        return wrapper;
    }

    private Map toUnderlineCase(Map condition) {
        Map map = new HashMap();
        for (Object key : condition.keySet()) {
            Object value = condition.get(key);
            String underline = StrUtil.toUnderlineCase((String) key);
            map.put(underline, value);
        }
        return map;
    }

}
